
// Main header
#include "../Main.h"

// My header
#include "TreeView.h"

// Fridge
#include "../Controller/Controller_Main.h"
#include "../FileTools.h"
#include "../MathsHelper.h"
#include "Panel.h"
#include "../Input.h"
#include "../InputKeys.h"
#include "../SuperTree.h"
#include "../TypedList.h"
#include "../TextRender.h"

static const u_int uTREEVIEW_TITLE_TEXTCOLOUR			= 0xCCCCCCFF;
static const u_int uTREEVIEW_ENTRY_HEIGHT				= 20;
static const u_int uTREEVIEW_BACK_BUTTON_HEIGHT			= 24;
static const u_int uTREEVIEW_BACK_BUTTON_TEXT_ENABLED	= 0x222222FF;
static const u_int uTREEVIEW_BACK_BUTTON_TEXT_DISABLED	= 0xCCCCCCFF;
static const u_int uTREEVIEW_BACK_BUTTON_DIVIDER_COL	= 0xCCCCCCFF;

///////////////////////////////////////////////////
// TreeView
///////////////////////////////////////////////////

TreeView::TreeView( Widget* pxParent ) : Panel( pxParent )
{
	m_pxTreeViewItems = new SuperTree<Button>( false );
	m_xCurrentRoot = TREE_HANDLE_HEAD;
	m_bBorder = true;
	m_pxBackButton = new Button( this );
	if( m_pxBackButton )
	{
		m_pxBackButton->SetFlatStyle( true );
		m_pxBackButton->SetLabel( "Back" );
		m_pxBackButton->SetCentreAlignText( false );
		m_pxBackButton->SetButtonPressCallback( BackButtonCallback, this );
		m_pxBackButton->SetEnabled( false );
	}
	m_pfnDefaultBeginDragFunc = 0;
	m_pfnDefaultDragOverFunc = 0;
	m_pfnDefaultEndDragFunc = 0;
}

TreeView::~TreeView()
{
	delete m_pxTreeViewItems;
}

void TreeView::Render()
{
	if( !m_bVisible )
	{
		return;
	}

	Panel::Render();

	// Render a back button

	if( m_pxBackButton )
	{
		m_pxBackButton->Render();
	}

	const u_int uSwappedBackCol = MathsHelper::RGBAtoABGR( uTREEVIEW_BACK_BUTTON_DIVIDER_COL );
	glColor4ubv( reinterpret_cast<const GLubyte*>( &uSwappedBackCol ) );
	glLineWidth( 1.0f );

	glBegin( GL_LINES );

		glVertex2i( m_pxBackButton->GetResizedX(), m_pxBackButton->GetResizedY() + m_pxBackButton->GetResizedHeight() );
		glVertex2i( m_pxBackButton->GetResizedX() + m_pxBackButton->GetResizedWidth(), m_pxBackButton->GetResizedY() + m_pxBackButton->GetResizedHeight() );

	glEnd();

	// Render the name of the current root

	Button* pxCurrentRoot = m_pxTreeViewItems->Get( m_xCurrentRoot );
	const char* szText = pxCurrentRoot ? pxCurrentRoot->GetLabel() : 0 ;

	if( szText )
	{
		u_int uTextHeight, uTextWidth;

		TextRender::SetColour( uTREEVIEW_TITLE_TEXTCOLOUR );
		TextRender::SetFont( FONT_SANS_12 );
		TextRender::GetRenderSize( szText, uTextWidth, uTextHeight );
		TextRender::Print( szText, GetResizedX() + uBUTTON_HORZ_TEXT_MARGIN, GetResizedY() + uTREEVIEW_BACK_BUTTON_HEIGHT + 5 + uTREEVIEW_ENTRY_HEIGHT / 2 - uTextHeight / 2 );
	}

	// Render the tree items on this level

	SuperTreeIter< Button >xIter( m_pxTreeViewItems, m_xCurrentRoot );

	while( !xIter.Done() )
	{
		Button* pxTreeViewEntry = xIter.Get( true );
		pxTreeViewEntry->Render();
	}
}

void TreeView::Update()
{
	SuperTreeIter< Button >xIter( m_pxTreeViewItems, m_xCurrentRoot );

	const Input* pxInputHandler = Controller_Main::GetInputHandler();

	while( !xIter.Done() )
	{
		Button* pxTreeViewEntry = xIter.Get();
		pxTreeViewEntry->Update();

		void* pxFFileInfo = 0;
		u_int uDataSize = 0;
		pxTreeViewEntry->GetUserData( pxFFileInfo, uDataSize );

		if( pxTreeViewEntry->MouseInWidget() && pxInputHandler->MouseButtonPressed( INPUT_MOUSE_BUTTON_LEFT ) && reinterpret_cast< FFileInfo* >( pxFFileInfo )->IsDirectory() )
		{
			m_xCurrentRoot = xIter.GetHandle();
		}

		xIter.Next();
	}

	// update the widget positions
	UpdateCurrentRoot( m_xCurrentRoot );

	Panel::Update();
}

void TreeView::UpdateCurrentRoot( const FHandle uNewRoot )
{
	const bool bCurrentRootHasParent = ( uNewRoot != TREE_HANDLE_HEAD );

	m_xCurrentRoot = uNewRoot;

	u_int uCurrentY = GetResizedY();

	if( m_pxBackButton )
	{
		m_pxBackButton->SetEnabled( bCurrentRootHasParent );
		m_pxBackButton->SetPosition( GetResizedX(), uCurrentY );
		m_pxBackButton->SetSize( GetResizedWidth(), uTREEVIEW_BACK_BUTTON_HEIGHT );

		uCurrentY += uTREEVIEW_BACK_BUTTON_HEIGHT;
	}

	uCurrentY += 5;

	if( bCurrentRootHasParent )
	{
		uCurrentY += uTREEVIEW_ENTRY_HEIGHT;
	}

	SuperTreeIter< Button >xIter( m_pxTreeViewItems, m_xCurrentRoot );

	while( !xIter.Done() )
	{
		Button* pxTreeViewEntry = xIter.Get( true );
		
		pxTreeViewEntry->SetPosition( GetResizedX(), uCurrentY );
		pxTreeViewEntry->SetSize( GetResizedWidth(), uTREEVIEW_ENTRY_HEIGHT );

		uCurrentY += uTREEVIEW_ENTRY_HEIGHT;
	}
}

void TreeView::BackButtonCallback ( void* pxInstance )
{
	if( pxInstance )
	{
		reinterpret_cast< TreeView* >( pxInstance )->_BackButtonCallback();
	}
}

void TreeView::_BackButtonCallback ( )
{
	if( m_xCurrentRoot != TREE_HANDLE_HEAD )
	{
		UpdateCurrentRoot( m_pxTreeViewItems->FindParent( m_xCurrentRoot ) );
	}
}


void TreeView::PopulateFromFileTree ( SuperTree< FFileInfo >* pxFileTree )
{
	m_pxTreeViewItems->Clear();

	PopulateFromFileTreeInternal( pxFileTree, TREE_HANDLE_HEAD );
}


void TreeView::PopulateFromFileTreeInternal ( SuperTree< FFileInfo >* pxFileTree, const FHandle xRoot )
{	
	// Add the items on this level
	SuperTreeIter< FFileInfo > xIter( pxFileTree, xRoot );
	
	while( !xIter.Done() )
	{
		FFileInfo* pxFFileInfo = xIter.Get();

		// Add file/directory
		Button* pxEntry = new Button( 0 );

		pxEntry->SetFlatStyle( true );
		pxEntry->SetCentreAlignText( false );
		pxEntry->SetRenderArrow( pxFFileInfo->IsDirectory() );
		
		pxEntry->SetLabel( pxFFileInfo->GetName() );
		
		// Use the FFileInfo structure as the data for this entry
		pxEntry->SetUserData( pxFFileInfo, sizeof( FFileInfo ) );

		// Set drag drop callbacks
		pxEntry->SetBeginDragDropCallback( m_pfnDefaultBeginDragFunc );
		pxEntry->SetDragOverCallback( m_pfnDefaultDragOverFunc );
		pxEntry->SetEndDragDropCallback( m_pfnDefaultEndDragFunc );

		m_pxTreeViewItems->Add( pxEntry, xRoot, xIter.GetHandle() );

		if( pxFFileInfo->IsDirectory() )
		{
			PopulateFromFileTreeInternal( pxFileTree, xIter.GetHandle() );
		}

		xIter.Next();
	}
}

void TreeView::SetDefaultBeginDragDropCallback( const BeginDragDropCallback pfnBeginDragDrop )
{
	m_pfnDefaultBeginDragFunc = pfnBeginDragDrop;
}

void TreeView::SetDefaultDragOverCallback( const DragOverCallback pfnDragOver )
{
	m_pfnDefaultDragOverFunc = pfnDragOver;
}

void TreeView::SetDefaultEndDragDropCallback( const EndDragDropCallback pfnEndDragDrop )
{
	m_pfnDefaultEndDragFunc = pfnEndDragDrop;
}

Widget* TreeView::FindChildWidgetAt ( const u_int uX, const u_int uY )
{
	if	(	( uX > GetResizedX() )
		&&	( uX < GetResizedX() + GetResizedWidth() )
		&&	( uY > GetResizedY() )
		&&	( uY < GetResizedY() + GetResizedHeight() ) )
	{
		// We cant have regular children, but our visible treeview entries should count as children
		Button* pxCurrentRoot = m_pxTreeViewItems->Get( m_xCurrentRoot );
		
		if( pxCurrentRoot )
		{
			SuperTreeIter< Button >xIter( m_pxTreeViewItems, m_xCurrentRoot );

			while( !xIter.Done() )
			{
				Button* pxTreeViewEntry = xIter.Get( true );
				Widget* pxFound = pxTreeViewEntry->FindChildWidgetAt( uX, uY );

				if( pxFound )
				{
					return pxFound;
				}
			}
		}

		// Not in child, but in us
		return this;
	}

	// Not inside us
	return 0;
}

//eof
